{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# SageMaker V3 In-Process Mode Example\n",
    "\n",
    "This notebook demonstrates how to use SageMaker V3 ModelBuilder in In-Process mode for fast local development and testing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import required libraries\n",
    "import uuid\n",
    "\n",
    "from sagemaker.serve.model_builder import ModelBuilder\n",
    "from sagemaker.serve.spec.inference_spec import InferenceSpec\n",
    "from sagemaker.serve.builder.schema_builder import SchemaBuilder\n",
    "from sagemaker.serve.mode.function_pointers import Mode"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 1: Define a Simple InferenceSpec\n",
    "\n",
    "Create a lightweight InferenceSpec for mathematical operations - perfect for in-process testing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MathInferenceSpec(InferenceSpec):\n",
    "    \"\"\"Simple math operations for IN_PROCESS testing.\"\"\"\n",
    "    \n",
    "    def load(self, model_dir: str):\n",
    "        \"\"\"Load a simple math 'model'.\"\"\"\n",
    "        return {\"operation\": \"multiply\", \"factor\": 2.0}\n",
    "    \n",
    "    def invoke(self, input_object, model):\n",
    "        \"\"\"Perform math operation.\"\"\"\n",
    "        if isinstance(input_object, dict) and \"numbers\" in input_object:\n",
    "            numbers = input_object[\"numbers\"]\n",
    "        elif isinstance(input_object, list):\n",
    "            numbers = input_object\n",
    "        else:\n",
    "            numbers = [float(input_object)]\n",
    "        \n",
    "        factor = model[\"factor\"]\n",
    "        result = [num * factor for num in numbers]\n",
    "        \n",
    "        return {\"result\": result, \"operation\": f\"multiply by {factor}\"}\n",
    "\n",
    "print(\"Math InferenceSpec defined successfully!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 2: Create Schema Builder\n",
    "\n",
    "Define the expected input and output format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create schema builder for math operations\n",
    "sample_input = {\"numbers\": [1.0, 2.0, 3.0]}\n",
    "sample_output = {\"result\": [2.0, 4.0, 6.0], \"operation\": \"multiply by 2.0\"}\n",
    "schema_builder = SchemaBuilder(sample_input, sample_output)\n",
    "\n",
    "print(\"Schema builder created successfully!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Configure ModelBuilder for In-Process Mode\n",
    "\n",
    "Set up ModelBuilder to run in IN_PROCESS mode for fast local execution."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Configuration\n",
    "MODEL_NAME_PREFIX = \"inprocess-math-model\"\n",
    "ENDPOINT_NAME_PREFIX = \"inprocess-math-endpoint\"\n",
    "\n",
    "# Generate unique identifiers\n",
    "unique_id = str(uuid.uuid4())[:8]\n",
    "model_name = f\"{MODEL_NAME_PREFIX}-{unique_id}\"\n",
    "endpoint_name = f\"{ENDPOINT_NAME_PREFIX}-{unique_id}\"\n",
    "\n",
    "# Create ModelBuilder in IN_PROCESS mode\n",
    "inference_spec = MathInferenceSpec()\n",
    "model_builder = ModelBuilder(\n",
    "    inference_spec=inference_spec,\n",
    "    schema_builder=schema_builder,\n",
    "    mode=Mode.IN_PROCESS  # This is the key difference!\n",
    ")\n",
    "\n",
    "print(f\"ModelBuilder configured for in-process model: {model_name}\")\n",
    "print(f\"Target endpoint: {endpoint_name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 4: Build the Model\n",
    "\n",
    "Build the model - this is very fast in in-process mode!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Build the model\n",
    "core_model = model_builder.build(model_name=model_name)\n",
    "print(f\"Model Successfully Created: {core_model.model_name}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 5: Deploy Locally\n",
    "\n",
    "Deploy the model locally - no containers or AWS resources needed!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Deploy locally in in-process mode\n",
    "local_endpoint = model_builder.deploy_local(endpoint_name=endpoint_name)\n",
    "print(f\"Local Endpoint Successfully Created: {local_endpoint.endpoint_name}\")\n",
    "print(\"Note: This runs entirely in your Python process - no containers!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 6: Test the In-Process Model\n",
    "\n",
    "Test various mathematical operations with instant responses."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Test 1: Simple multiplication\n",
    "test_data_1 = {\"numbers\": [1.0, 2.0, 3.0]}\n",
    "\n",
    "result_1 = local_endpoint.invoke(\n",
    "    body=test_data_1,\n",
    "    content_type=\"application/json\"\n",
    ")\n",
    "\n",
    "print(f\"Test 1 - Simple multiplication: {result_1.body}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Test 2: Larger numbers\n",
    "test_data_2 = {\"numbers\": [10.5, 20.3, 30.7, 40.1]}\n",
    "\n",
    "result_2 = local_endpoint.invoke(\n",
    "    body=test_data_2,\n",
    "    content_type=\"application/json\"\n",
    ")\n",
    "\n",
    "print(f\"Test 2 - Larger numbers: {result_2.body}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Test 3: Single number (alternative input format)\n",
    "test_data_3 = [5.0]  # Direct list format\n",
    "\n",
    "result_3 = local_endpoint.invoke(\n",
    "    body=test_data_3,\n",
    "    content_type=\"application/json\"\n",
    ")\n",
    "\n",
    "print(f\"Test 3 - Single number: {result_3.body}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 7: Performance Testing\n",
    "\n",
    "Demonstrate the speed advantage of in-process mode."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "# Performance test - multiple rapid requests\n",
    "start_time = time.time()\n",
    "num_requests = 100\n",
    "\n",
    "for i in range(num_requests):\n",
    "    test_data = {\"numbers\": [i, i+1, i+2]}\n",
    "    result = local_endpoint.invoke(\n",
    "        body=test_data,\n",
    "        content_type=\"application/json\"\n",
    "    )\n",
    "\n",
    "end_time = time.time()\n",
    "total_time = end_time - start_time\n",
    "avg_time = total_time / num_requests\n",
    "\n",
    "print(f\"Performance Test Results:\")\n",
    "print(f\"- Total requests: {num_requests}\")\n",
    "print(f\"- Total time: {total_time:.3f} seconds\")\n",
    "print(f\"- Average time per request: {avg_time*1000:.2f} ms\")\n",
    "print(f\"- Requests per second: {num_requests/total_time:.1f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 8: Clean Up\n",
    "\n",
    "Clean up the in-process resources (very fast!)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Clean up in-process endpoint\n",
    "if local_endpoint and hasattr(local_endpoint, 'in_process_mode_obj'):\n",
    "    if local_endpoint.in_process_mode_obj:\n",
    "        local_endpoint.in_process_mode_obj.destroy_server()\n",
    "\n",
    "print(\"In-process model and endpoint successfully cleaned up!\")\n",
    "print(\"Note: No AWS resources were created, so no cloud cleanup needed.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "This notebook demonstrated:\n",
    "1. Creating a simple InferenceSpec for mathematical operations\n",
    "2. Configuring ModelBuilder for IN_PROCESS mode\n",
    "3. Building and deploying models locally without containers\n",
    "4. Testing with various input formats\n",
    "5. Performance testing showing the speed of in-process execution\n",
    "6. Quick cleanup with no AWS resources\n",
    "\n",
    "## Benefits of In-Process Mode:\n",
    "- **Ultra-fast**: No container startup time\n",
    "- **No AWS costs**: Runs entirely locally\n",
    "- **Perfect for development**: Rapid iteration and testing\n",
    "- **Easy debugging**: Direct access to Python objects\n",
    "- **Lightweight**: Minimal resource usage\n",
    "\n",
    "Use in-process mode for development, testing, and lightweight inference tasks!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "venv-test",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
